/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-07-12     18421       the first version
 */

#include "switch.h"
#include "netupdata.h"
static struct rt_thread switchThread; //线程控制块
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t switchThread_stack[1024]; //线程栈

uint8_t key_ONOFF_Status[KEY_NUM_ALL]={0}; //按键控制时，电路开关状态。0关闭，1打开

uint8_t netCmdCtrlRunflag=0;
volatile static uint8_t powerCurrentStatus=0; //1连接 0未连接


static void swfirstStatusGet();

#define SW1_Write(status) HAL_GPIO_WritePin(SW8_GPIO_Port, SW8_Pin,status)
#define SW2_Write(status) HAL_GPIO_WritePin(SW7_GPIO_Port, SW7_Pin,status)
#define SW3_Write(status) HAL_GPIO_WritePin(SW6_GPIO_Port, SW6_Pin,status)
#define SW4_Write(status) HAL_GPIO_WritePin(SW5_GPIO_Port, SW5_Pin,status)
#define SW5_Write(status) HAL_GPIO_WritePin(SW4_GPIO_Port, SW4_Pin,status)
#define SW6_Write(status) HAL_GPIO_WritePin(SW3_GPIO_Port, SW3_Pin,status)
#define SW7_Write(status) HAL_GPIO_WritePin(SW2_GPIO_Port, SW2_Pin,status)
#define SW8_Write(status) HAL_GPIO_WritePin(SW1_GPIO_Port, SW1_Pin,status)

#define POWER12V_Read()     HAL_GPIO_ReadPin(POWER12V_GPIO_Port,POWER12V_Pin)
/* 按键信息 */
struct KeyInfo keyInfo;
struct swInfo swinfo;
/* 按键变化处理回调 */
void (* KeyChangeDealWith)(uint8_t keyNum,uint8_t state);


static struct UpCtrlPortsSwitch updata={0};
static struct cmdCtrl  cmdCtrlInfo={0};

void MenukeyResult(uint8_t keyNum,uint8_t state);

/*网络指令控制*/
void netCmdCtrl(int swNum, int status,const char* id)
{
    if(swNum>7 || swNum<0)
    {
        //按键数字不对
        return ;
    }
    if (keyInfo.Control_Enable[swNum] == 1)
    {
        cmdCtrlInfo.SwStatus = status;
        cmdCtrlInfo.swNum = swNum;
        netCmdCtrlRunflag=1;
        updata_cmdReback(0, id,1);
    }
    else
    {
        updata_cmdReback(1,id,1);
    }
}
static void sw_gpio_init()
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

     /* GPIO Ports Clock Enable */
     __HAL_RCC_GPIOC_CLK_ENABLE();
     __HAL_RCC_GPIOA_CLK_ENABLE();
     __HAL_RCC_GPIOB_CLK_ENABLE();
     __HAL_RCC_GPIOD_CLK_ENABLE();

     /*Configure GPIO pin Output Level */
     HAL_GPIO_WritePin(GPIOC, SW8_Pin|SW7_Pin|SW1_Pin|SW6_Pin
                             |SW5_Pin, GPIO_PIN_RESET);

     /*Configure GPIO pin Output Level */
     HAL_GPIO_WritePin(GPIOA, SW3_Pin|SW4_Pin|SW2_Pin, GPIO_PIN_RESET);

     /*Configure GPIO pins : SW2_INB_Pin SW3_INA_Pin SW3_INB_Pin */
     GPIO_InitStruct.Pin = SW2_INB_Pin|SW3_INA_Pin|SW3_INB_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

     /*Configure GPIO pins : SW8_Pin SW7_Pin SW1_Pin SW6_Pin
                              SW5_Pin */
     GPIO_InitStruct.Pin = SW8_Pin|SW7_Pin|SW1_Pin|SW6_Pin
                             |SW5_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Pull = GPIO_PULLDOWN;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

     /*Configure GPIO pins : POWER12V_Pin KEY4_Pin KEY3_Pin KEY2_Pin
                              KEY1_Pin */
     GPIO_InitStruct.Pin = POWER12V_Pin|KEY4_Pin|KEY3_Pin|KEY2_Pin
                             |KEY1_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_PULLUP;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

     /*Configure GPIO pins : SW2_INA_Pin SW1_INB_Pin SW4_INA_Pin SW4_INB_Pin */
     GPIO_InitStruct.Pin = SW2_INA_Pin|SW1_INB_Pin|SW4_INA_Pin|SW4_INB_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_PULLUP;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

     /*Configure GPIO pins : SW5_INA_Pin SW5_INB_Pin SW1_INA_Pin KEY5_Pin
                              KEY6_Pin KEY7_Pin KEY8_Pin SW8_INA_Pin
                              SW7_INB_Pin SW7_INA_Pin SW6_INB_Pin SW6_INA_Pin */
     GPIO_InitStruct.Pin = SW5_INA_Pin|SW5_INB_Pin|SW1_INA_Pin|KEY5_Pin
                             |KEY6_Pin|KEY7_Pin|KEY8_Pin|SW8_INA_Pin
                             |SW7_INB_Pin|SW7_INA_Pin|SW6_INB_Pin|SW6_INA_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_PULLUP;
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

     /*Configure GPIO pins : SW3_Pin SW4_Pin SW2_Pin */
     GPIO_InitStruct.Pin = SW3_Pin|SW4_Pin|SW2_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Pull = GPIO_PULLDOWN;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

     /*Configure GPIO pin : SW8_INB_Pin */
     GPIO_InitStruct.Pin = SW8_INB_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(SW8_INB_GPIO_Port, &GPIO_InitStruct);
}







/**
 * @brief 获取按键状态
 * @param keyNum 按键号
 * @return
 */
static KeyStatus GetKeyStatus(uint8_t keyNum)
{
    uint8_t tKeyStatus = 0;
    switch(keyNum){
        case 7:tKeyStatus = key8_read();break;
        case 6:tKeyStatus = key7_read();break;
        case 5:tKeyStatus = key6_read();break;
        case 4:tKeyStatus = key5_read();break;
        case 3:tKeyStatus = key4_read();break;
        case 2:tKeyStatus = key3_read();break;
        case 1:tKeyStatus = key2_read();break;
        case 0:tKeyStatus = key1_read();break;

        default:break;
    }
    if(tKeyStatus == LED_HARDWARE_DOWN){
        return KEYDOWN;
    }
    else{
        return KEYUP;
    }
}
/**
  *@brief  按键扫描
  *@param  None
  *@retval None
  */
void ScanKeyStatus(void)
{
    uint8_t i;
    KeyStatus tState;

    for(i = 0; i < KEY_NUM_ALL; i ++){//循环扫描
        tState = GetKeyStatus(i);
        if(tState == KEYDOWN && keyInfo.stepFlag[i] == 0){//启动消抖
            keyInfo.filterCount[i] = GetTimer1Tick();
            keyInfo.stepFlag[i] = 1;
        }
        else if(tState == KEYDOWN && keyInfo.stepFlag[i] == 1){
            if(GetTimer1IntervalTick(keyInfo.filterCount[i]) > 10){//真实变位
                keyInfo.currentStatus[i] = KEYDOWN;
                KeyChangeDealWith(i,KEYDOWN);//回调
                keyInfo.stepFlag[i] = 2;
            }
        }
        else if(tState == KEYUP && keyInfo.stepFlag[i] != 0){//等待抬起
            keyInfo.currentStatus[i] = KEYUP;
            if(keyInfo.stepFlag[i] == 2){
                KeyChangeDealWith(i,KEYUP);//回调
            }
            keyInfo.stepFlag[i] = 0;
        }
    }
}
/**
 *
 * @param swNum 1-8
 * @param port 0A端口 1B端口
 */
static SwStatus swRead(uint8_t swNum)
{

    uint8_t swAStatus=1, swBStatus=1;
    switch (swNum)
    {
    case 0:
        swAStatus = SW1A_read();
        swBStatus = SW1B_read();
        break;
    case 1:
        swAStatus = SW2A_read();
        swBStatus = SW2B_read();

        break;
    case 2:
        swAStatus = SW3A_read();
        swBStatus = SW3B_read();

        break;
    case 3:
        swAStatus = SW4A_read();
        swBStatus = SW4B_read();

        break;
    case 4:
        swAStatus = SW5A_read();
        swBStatus = SW5B_read();

        break;
    case 5:
        swAStatus = SW6A_read();
        swBStatus = SW6B_read();

        break;
    case 6:
        swAStatus = SW7A_read();
        swBStatus = SW7B_read();

        break;
    case 7:
        swAStatus = SW8A_read();
        swBStatus = SW8B_read();
        break;
    default:
        break;
    }

    if (swAStatus == 1 && swBStatus == 0)
    {
        return FORCEON;
    }
    else if (swAStatus == 1 && swBStatus == 1)
    {
        return FORCEOFF;
    }
    else if (swAStatus == 0 && swBStatus == 1)
    {
        return CONTROL;
    }
    else
        return STATUSERR;
}

void swChangeDealWith(uint8_t swnum,uint8_t status)
{

        rt_kprintf("SW(%d)Status Change ,Current status(%d)\n", swnum + 1, swinfo.swstatus[swnum]);
        //状态设置和上报
        if (status == STATUSERR)
        {
            rt_kprintf("SW hardware detect ERROR\n");
        }
        else if (status == FORCEOFF || status == FORCEON)
        {
            keyInfo.Control_Enable[swnum] = 0;

            key_ONOFF_Status[swnum] = 0;
            swWrite(swnum, key_ONOFF_Status[swnum]); //关闭控制输出引脚

        }
        else
            keyInfo.Control_Enable[swnum] = 1;

        if (status != STATUSERR && powerCurrentStatus !=0)
        {
            updata.BizType = 1; //触发类型为 按键触发
            updata.HandleType = 2; //事件类型为模式切换
            updata.CtrlPort = swnum + 1;
            updata.SwitchState = key_ONOFF_Status[swnum];
            updata.ForceState = status;
            updata_SwStaStruct_Set(&updata); //设置数据同时通知上报

        }

}
void ScanSwitchStatus()
{
    SwStatus status;
    for (int i = 0; i < 8; i++)
    {
        status = swRead(i);

        if (status != swinfo.swstatus[i] && swinfo.stepFlag[i] == 0)
        { //启动消抖
            swinfo.filterCount[i] = GetTimer1Tick();
            swinfo.stepFlag[i] = 1;
        }
        else if (status != swinfo.swstatus[i] && swinfo.stepFlag[i] == 1)
        {
            if (GetTimer1IntervalTick(swinfo.filterCount[i]) > 10)
            { //真实变位
                swinfo.swstatus[i] = status;
                swChangeDealWith(i, swinfo.swstatus[i]); //回调
                keyInfo.stepFlag[i] = 0;
            }
        }



    }
}


/**
  *@brief  按键驱动初始化
  *@param  None
  *@retval None
  */
void KeyDriverInit(void)
{
    sw_gpio_init();
    KeyChangeDealWith = MenukeyResult;
}

/**
 * 输出控制
 * @param keyNum 开关号
 * @param state 状态 1开 0关
 */
void swWrite(uint8_t keyNum, uint8_t state)
{
    switch (keyNum)
    {
    case KEY1DOWN:
        SW1_Write(state);
        break;
    case KEY2DOWN:
        SW2_Write(state);
        break;
    case KEY3DOWN:
        SW3_Write(state);
        break;
    case KEY4DOWN:

        SW4_Write(state);
        break;
    case KEY5DOWN:
        SW5_Write(state);
        break;
    case KEY6DOWN:
        SW6_Write(state);

        break;
    case KEY7DOWN:
        SW7_Write(state);

        break;
    case KEY8DOWN:
        SW8_Write(state);
        break;
    default:
        break;
    }
}

/* 菜单按键枚举 */
enum MenuKeyIs menuKeyState;   //使用示例
/**
  *@brief  菜单按键处理
  *@param  按键值
  *@param  产生状态
  *@retval None
  */
void MenukeyResult(uint8_t keyNum, uint8_t state)
{
    if (state != KEYDOWN || keyInfo.Control_Enable[keyNum] != 1)
    {
        return;
    }

    key_ONOFF_Status[keyNum] = !key_ONOFF_Status[keyNum];

    swWrite(keyNum, key_ONOFF_Status[keyNum]);

    updata.BizType = 1; //触发类型为 按键触发
    updata.HandleType = 1; //事件类型为模式切换
    updata.CtrlPort = keyNum+ 1;
    updata.SwitchState = key_ONOFF_Status[keyNum];
    updata.ForceState = 2;
    updata_SwStaStruct_Set(&updata); //设置数据同时通知上报
    rt_kprintf("key(%d) press and power status(%d)\n",keyNum+1,key_ONOFF_Status[keyNum]);

}


/**
  *@brief 获取开始计时数
  *@param  None
  *@retval beginTick  计时开始数，
  */
uint32_t GetTimer1Tick(void)
{
    return rt_tick_get();
}

/**
  *@brief 获取间隔周期数
  *@param  beginTick  计时开始数，由GetTimer1Tick()函数获得
  *@retval 间隔周期数
  */
uint32_t GetTimer1IntervalTick(uint32_t beginTick)
{
    uint32_t temptick;
    temptick = GetTimer1Tick();
    if(beginTick <= temptick){
        return (temptick - beginTick);
    }
    else{
        return ((0xFFFFFFFF - beginTick)+temptick);
    }
}

static void swfirstStatusGet()
{

    for(int i=0;i<8;i++)
    {
        swinfo.swstatus[i] = swRead(i);
        keyInfo.Control_Enable[i]=(swinfo.swstatus[i]==2)?1:0;
    }
    uint8_t status=POWER12V_Read();
    struct updataAllStruct updata = {
            .BizType = 0, //触发类型为 上线触发
            .Electric=!status,
    };
    rt_memcpy(updata.SwSta,key_ONOFF_Status,sizeof(key_ONOFF_Status));
    rt_memcpy(updata.ForceSta,swinfo.swstatus,sizeof(swinfo.swstatus));
    updata_AllStruct_Set(&updata); //设置数据同时通知上报
    updataNotify(0,updata.BizType);

}


/**
 *
 * @return 1连接 0未连接
 */
uint8_t scanPowerStatus()
{

    if (POWER12V_Read())  //12V断开
    {
        if( powerCurrentStatus!=0)
        {
            struct UpEvents updata = {
                    .BizType = 3, //触发类型为 异常触发
                    .EventType = 1, //事件类型为 断电告警
                    .CtrlPort = 0 };
            updata_EventStruct_Set(&updata); //设置数据同时通知上报
            rt_kprintf("12V POWER DISCONNCET\n");

            rt_thread_mdelay(3000);
        }
        powerCurrentStatus=0;

//        rt_kprintf("12V POWER DISCONNCET,4g DEVICE CAN'T NORMAL WORK \n");
        return 0;
    }
    else
    {

        if (powerCurrentStatus != 1)
        {
            rt_kprintf("[PowerOn] Device Power Up\n");
            swfirstStatusGet();//上电设置
            updataNotify(6, 0);//上报ota版本

        }
        powerCurrentStatus=1;
        return 1;
    }

}



void scanNetCmd()
{
    if (netCmdCtrlRunflag && key_ONOFF_Status[cmdCtrlInfo.swNum]!=cmdCtrlInfo.SwStatus)
    {
        netCmdCtrlRunflag = 0;
        swWrite(cmdCtrlInfo.swNum, cmdCtrlInfo.SwStatus);
        key_ONOFF_Status[cmdCtrlInfo.swNum]=cmdCtrlInfo.SwStatus;
        updata.BizType = 2; //触发类型为 按键触发
        updata.HandleType = 1; //事件类型为按键开关
        updata.CtrlPort = cmdCtrlInfo.swNum + 1;
        updata.SwitchState = key_ONOFF_Status[cmdCtrlInfo.swNum];
        updata.ForceState = 2;
        updata_SwStaStruct_Set(&updata); //设置数据同时通知上报
        rt_kprintf("net cmd set key (%d)  status to(%d)\n", cmdCtrlInfo.swNum + 1,
                      key_ONOFF_Status[cmdCtrlInfo.swNum]);
    }
    else if(netCmdCtrlRunflag && key_ONOFF_Status[cmdCtrlInfo.swNum]==cmdCtrlInfo.SwStatus){
        netCmdCtrlRunflag=0;
        rt_kprintf(" key (%d)  status is (%d),dont need set\n", cmdCtrlInfo.swNum + 1,
                              key_ONOFF_Status[cmdCtrlInfo.swNum]);
    }

}
//定时触发上报全览数据
void swTimeUp()
{

    rt_kprintf("Trigger the timer every (5)minutes Data is reported \n");
    uint8_t status = POWER12V_Read();

    struct updataAllStruct updata = {
            .BizType = 4, //触发类型为 定时触发
            .Electric = !status, };
    rt_memcpy(updata.SwSta, key_ONOFF_Status, sizeof(key_ONOFF_Status));
    rt_memcpy(updata.ForceSta, swinfo.swstatus, sizeof(swinfo.swstatus));

    updata_AllStruct_Set(&updata); //设置数据同时通知上报
    updataNotify(0, updata.BizType);

}
static void switchThreadEntry(void* para)
{
//    swfirstStatusGet();

    while(1)
    {

        scanPowerStatus();
        ScanSwitchStatus();

        ScanKeyStatus();
        scanNetCmd();
        rt_thread_mdelay(50);
    }


}
int switchInit()
{
    KeyDriverInit();
    return 0;

}
int switchappinit()
{
    rt_thread_init(&switchThread, "swThread", switchThreadEntry,
    RT_NULL, &switchThread_stack[0], sizeof(switchThread_stack), 18, 15);
    if (RT_EOK != rt_thread_startup(&switchThread))
    {
        rt_kprintf("switchThread Init err\n");
        return 1;
    }
    return 0;
}
INIT_BOARD_EXPORT(switchInit);
INIT_APP_EXPORT(switchappinit);



